package fons.model.query.fun;

import java.util.Map;
import java.util.Set;

import com.google.common.collect.Maps;

import fons.model.ontology.CompositeMeasurement;
import fons.model.ontology.Dimension;
import fons.model.ontology.Role;
import fons.model.ontology.interfaces.Measurement;

public enum Operator {
	SUM {
		@Override
		public double apply(double one, double two) {
			return one+two;
		}

		@Override
		public Measurement apply(Measurement a, Measurement b) {
			if (a == b) return a;
			else throw new IllegalArgumentException(a.getQualifiedName() + " und " + b.getQualifiedName()
					+ " sind inkompatibel!");
		}	
	},
	DIFFERENCE {
		@Override
		public double apply(double one, double two) {
			return one-two;
		}

		@Override
		public Measurement apply(Measurement a, Measurement b) {
			return SUM.apply(a, b);
		}
	},
	
	MULTIPLICATION  {
		@Override
		public double apply(double one, double two) {
			return one*two;
		}

		@Override
		public Measurement apply(Measurement a, Measurement b) {
			return CompositeMeasurement.multiply(a, b);
		}
	},
	DIVISION {
		@Override
		public double apply(double one, double two) {
			return one/two;
		}

		@Override
		public Measurement apply(Measurement aBy, Measurement b) {
			return CompositeMeasurement.divide(aBy, b);
		}
	};
	
	public abstract double apply(double one, double two);
	public abstract Measurement apply(Measurement a, Measurement b);
	public Map<Role, Set<Dimension>> apply(
			Map<Role, Set<Dimension>> a,
			Map<Role, Set<Dimension>> b) {
		
		Map<Role, Set<Dimension>> result = Maps.newHashMap();
		
		for (Role role: a.keySet()) {
			result.put(role, a.get(role));
		}
		
		for (Role role: b.keySet()) {
			if (result.containsKey(role)) {
				result.get(role).addAll(b.get(role));
			} else {
				result.put(role, b.get(role));
			}
		}
		
		return result;
	}
}